---
title: Dialog
description: Using the dialog machine in your project.
package: "@zag-js/dialog"
---

A dialog is a window overlaid on either the primary window or another dialog
window. Content behind a modal dialog is inert, meaning that users cannot
interact with it.

<Resources pkg="@zag-js/dialog" />

<Showcase id="Dialog" />

**Features**

- Supports modal and non-modal modes
- Focus is trapped and scrolling is blocked in the modal mode
- Provides screen reader announcements via rendered title and description
- Pressing `Esc` closes the dialog

## Installation

To use the dialog machine in your project, run the following command in your
command line:

<CodeSnippet id="dialog/installation.mdx" />

## Anatomy

To use the dialog component correctly, you'll need to understand its anatomy and
how we name its parts.

> Each part includes a `data-part` attribute to help identify them in the DOM.

<Anatomy id="dialog" />

## Usage

First, import the dialog package into your project

```jsx
import * as dialog from "@zag-js/dialog"
```

The dialog package exports two key functions:

- `machine` — The state machine logic for the dialog widget as described in
  WAI-ARIA specification.
- `connect` — The function that translates the machine's state to JSX attributes
  and event handlers.

> You'll need to provide a unique `id` to the `useMachine` hook. This is used to
> ensure that every part has a unique identifier.

Next, import the required hooks and functions for your framework and use the
dialog machine in your project 🔥

<CodeSnippet id="dialog/usage.mdx" />

### Managing focus within the dialog

When the dialog opens, it automatically sets focus on the first focusable
elements and traps focus within it, so that tabbing is constrained to it.

To control the element that should receive focus on open, pass the
`initialFocusEl` context (which can be an element or a function that returns an
element)

<CodeSnippet id="dialog/initial-focus.mdx" />

To set the element that receives focus when the dialog closes, pass the
`finalFocusEl` in the similar fashion as shown above.

### Closing the dialog on interaction outside

By default, the dialog closes when you click its overlay. You can set
`closeOnInteractOutside` to `false` if you want the modal to stay visible.

```jsx {2}
const service = useMachine(dialog.machine, {
  closeOnInteractOutside: false,
})
```

You can also customize the behavior by passing a function to the
`onInteractOutside` context and calling `event.preventDefault()`

```jsx {2-7}
const service = useMachine(dialog.machine, {
  onInteractOutside(event) {
    const target = event.target
    if (target?.closest("<selector>")) {
      return event.preventDefault()
    }
  },
})
```

### Listening for open state changes

When the dialog is opened or closed, the `onOpenChange` callback is invoked.

```jsx {2-7}
const service = useMachine(dialog.machine, {
  onOpenChange(details) {
    // details => { open: boolean }
    console.log("open:", details.open)
  },
})
```

### Controlled dialog

To control the dialog's open state, pass the `open` and `onOpenChange`
properties.

<CodeSnippet id="dialog/controlled.mdx" />

### Controlling the scroll behavior

When the dialog is open, it prevents scrolling on the `body` element. To disable
this behavior, set the `preventScroll` context to `false`.

```jsx {2}
const service = useMachine(dialog.machine, {
  preventScroll: false,
})
```

### Creating an alert dialog

The dialog has support for dialog and alert dialog roles. It's set to `dialog`
by default. To change it's role, pass the `role: alertdialog` property to the
machine's context.

That's it! Now you have an alert dialog.

```jsx {2}
const service = useMachine(dialog.machine, {
  role: "alertdialog",
})
```

> By definition, an alert dialog will contain two or more action buttons. We
> recommended setting focus to the least destructive action via `initialFocusEl`

## Styling guide

Earlier, we mentioned that each accordion part has a `data-part` attribute added
to them to select and style them in the DOM.

```css
[data-part="trigger"] {
  /* styles for the trigger element */
}

[data-part="backdrop"] {
  /* styles for the backdrop element */
}

[data-part="positioner"] {
  /* styles for the positioner element */
}

[data-part="content"] {
  /* styles for the content element */
}

[data-part="title"] {
  /* styles for the title element */
}

[data-part="description"] {
  /* styles for the description element */
}

[data-part="close-trigger"] {
  /* styles for the close trigger element */
}
```

### Open and closed state

The dialog has two states: `open` and `closed`. You can use the `data-state`
attribute to style the dialog or trigger based on its state.

```css
[data-part="content"][data-state="open|closed"] {
  /* styles for the open state */
}

[data-part="trigger"][data-state="open|closed"] {
  /* styles for the open state */
}
```

### Nested dialogs

When dialogs are nested (a dialog opened from within another dialog), the layer
stack automatically applies data attributes to help create visual hierarchy look

- `data-nested` - Applied to nested dialogs
- `data-has-nested` - Applied to dialogs that have nested dialogs open
- `--nested-layer-count` - CSS variable indicating the number of nested dialogs

```css
/* Scale down parent dialogs when they have nested children */
[data-part="content"][data-has-nested] {
  transform: scale(calc(1 - var(--nested-layer-count) * 0.05));
  transition: transform 0.2s ease-in-out;
}

/* Style nested dialogs differently */
[data-part="content"][data-nested] {
  border: 2px solid var(--accent-color);
}

/* Create depth effect using backdrop opacity */
[data-part="backdrop"][data-has-nested] {
  opacity: calc(0.4 + var(--nested-layer-count) * 0.1);
}
```

## Methods and Properties

### Machine Context

The dialog machine exposes the following context properties:

<ContextTable name="dialog" />

### Machine API

The dialog `api` exposes the following methods:

<ApiTable name="dialog" />

### Data Attributes

<DataAttrTable name="dialog" />

### CSS Variables

<CssVarTable name="dialog" />

## Accessibility

Adheres to the
[Alert and Message Dialogs WAI-ARIA design pattern](https://www.w3.org/WAI/ARIA/apg/patterns/alertdialog).

### Keyboard Interactions

<KeyboardTable name="dialog" />
